package com.itheima.mp.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.itheima.mp.domain.po.Address;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.domain.vo.AddressVO;
import com.itheima.mp.enums.UserStatus;
import com.itheima.mp.mapper.UserMapper;
import com.itheima.mp.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IUserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    /**
     * 扣除用户余额的方法
     * @param id 用户ID
     * @param amount 扣除金额
     * @throws IllegalArgumentException 当用户不存在或余额不足时抛出
     */
    @Override
    public void deduction(Long id, Integer amount) {
//        User user = this.getById(id);
//        if (user == null || user.getStatus()==2) {
//            throw new IllegalArgumentException("用户不存在或者已冻结!");
//        }
//        if (user.getBalance() < amount) {
//            throw new IllegalArgumentException("余额不足");
//        }
////        user.setBalance(user.getBalance() - amount);
//        userMapper.updateBalanceById(amount, id);
//        this.updateById(user);
//        log.info("用户{}扣除{}元成功", user.getUsername(), amount);

        //改造：
        //完成对用户状态校验
        //完成对用户余额校验
        //如果扣减余额为0，则将用户状态置为冻结（2）
        // 根据ID查询用户信息
        User user = this.getById(id);
        // 检查用户是否存在或已冻结（状态为2）
        if (user == null || user.getStatus() == UserStatus.FREEZE) {
            throw new IllegalArgumentException("用户不存在或者已冻结!");
        }
        // 检查用户余额是否足够扣除
        if (user.getBalance() < amount) {
            throw new IllegalArgumentException("余额不足");
        }
        // 计算扣除金额后的新余额
        Integer newBalance = user.getBalance()-amount;
        // 以下是两种更新方式的注释代码（被注释掉了）：
        // 方式1：直接更新用户余额
//        user.setBalance(user.getBalance() - amount);
        // 方式2：通过Mapper接口更新余额
//        userMapper.updateBalanceById(amount, id);
        //方法3：使用MyBatis-Plus的Lambda Update构造器更新用户信息
        this.lambdaUpdate()
                        .set(User::getBalance, newBalance)//设置余额
                        .set(newBalance==0, User::getStatus, 2)//设置状态为冻结（2）
                        .eq(User::getId, id)
                        .update();
        log.info("用户{}扣除{}元成功", user.getUsername(), amount);
    }

    /**
     * 根据用户ID查询用户信息及其关联的地址列表
     * @param id 用户ID
     * @return UserVO 包含用户信息和地址列表的视图对象
     */
    @Override
    public UserVO queryUserAndAddress(Long id) {
        // 根据ID获取用户实体对象
        User user = this.getById(id);
        // 将用户实体对象转换为视图对象
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        // 查询该用户关联的所有地址列表
        List<Address> list = Db.lambdaQuery(Address.class)
                .eq(Address::getUserId, id)
                .list();
        // 将地址实体列表转换为视图对象列表
        List<AddressVO> addressVOList = BeanUtil.copyToList(list, AddressVO.class);
        // 将地址列表设置到用户视图对象中
        userVO.setAddressList(addressVOList);
        // 返回包含完整信息的用户视图对象
        return userVO;

    }

    /**
     * 根据用户ID列表查询用户及其地址信息
     * @return 包含用户及其地址信息的UserVO列表
     */
    @Override
    public List<UserVO> queryUserAndAddressList(List<Long> ids) {
        // 根据ID列表查询用户信息
        List<User> userList = listByIds(ids);
        // 将用户实体列表转换为VO列表
        List<UserVO> userVOList = BeanUtil.copyToList(userList, UserVO.class);
        // 根据用户ID列表查询对应的地址信息
        List<Address> addressList = Db.lambdaQuery(Address.class)
                .in(Address::getUserId, ids)
                .list();
        // 将地址实体列表转换为VO列表
        List<AddressVO> addressVOs = BeanUtil.copyToList(addressList, AddressVO.class);
        // 将地址按用户ID分组，便于后续关联
        Map<Long, List<AddressVO>> collect = addressVOs.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        // 遍历用户VO列表，为每个用户设置其对应的地址列表
        for (UserVO userVO : userVOList) {
            List<AddressVO> addressVOList = collect.get(userVO.getId());
            userVO.setAddressList(addressVOList);
        }
        return userVOList;
    }
}
